package top.anydata.lifeofcode.lifesystem.service.sys.user.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.anydata.lifeofcode.lifesystem.dao.sys.user.ISysAuthUserRepository;
import top.anydata.lifeofcode.lifesystem.dao.sys.user.ISysAuthUserRoleRepository;
import top.anydata.lifeofcode.lifesystem.dto.sys.user.SysAuthUserDto;
import top.anydata.lifeofcode.lifesystem.entity.sys.user.SysAuthRoleEntity;
import top.anydata.lifeofcode.lifesystem.entity.sys.user.SysAuthUserEntity;
import top.anydata.lifeofcode.lifesystem.entity.sys.user.SysAuthUserRoleEntity;
import top.anydata.lifeofcode.lifesystem.service.sys.user.IAuthUserService;
import top.anydata.lifeofcode.lifesystem.service.sys.user.IJwtTokenService;
import top.anydata.lifeofcode.lifesystem.web.requests.admin.SigninRequest;
import top.anydata.lifeofcode.lifesystem.web.requests.admin.SignUpRequest;
import top.anydata.lifeofcode.lifesystem.web.responses.admin.JwtAuthenticationResponse;

import java.util.Optional;

/**
 * 功能描述:
 *
 * @author <a href="mailto:caingao@anydata.top">CainGao</a>
 * @version V_1.0
 * @date 2023/8/31 6:03 PM
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthUserServiceImpl  implements IAuthUserService {

    private final ISysAuthUserRepository sysAuthUserDao;

    private final ISysAuthUserRoleRepository sysAuthUserRoleRepository;

    private final PasswordEncoder passwordEncoder;

    private final IJwtTokenService jwtTokenService;

    private final AuthenticationManager authenticationManager;

    private final ModelMapper modelMapper = new ModelMapper();

    @Override
    public JwtAuthenticationResponse signup(SignUpRequest request) {
        Optional<SysAuthUserEntity> authUserEntityOptional =
                sysAuthUserDao.findByEmail(request.getEmail());
        if(authUserEntityOptional.isPresent()) {
            throw new IllegalArgumentException("Email Address already in use.");
        }
        var user = SysAuthUserEntity.builder().username(request.getFirstName()).nickname(request.getLastName())
                .email(request.getEmail()).password(passwordEncoder.encode(request.getPassword()))
                .build();
        sysAuthUserDao.save(user);
        var jwt = jwtTokenService.generateToken(user);
        return JwtAuthenticationResponse.builder().token(jwt).build();
    }

    @Override
    public JwtAuthenticationResponse signin(SigninRequest request) {
        authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        request.getEmail(),
                        request.getPassword()
                )
        );
        var sysAuthUserEntity =
                sysAuthUserDao.findByEmail(request.getEmail())
                .orElseThrow(() -> new IllegalArgumentException("Invalid email or password."));
        var jwt = jwtTokenService.generateToken(sysAuthUserEntity);
        return JwtAuthenticationResponse.builder().token(jwt).build();
    }

    @Override
    public Page<SysAuthUserDto> listUser(Integer page, Integer size) {
        Page<SysAuthUserEntity> sysAuthUserEntities = sysAuthUserDao.findAllNotDeleted(PageRequest.of(page, size));
        return sysAuthUserEntities.map(sysAuthUserEntity -> modelMapper.map(sysAuthUserEntity, SysAuthUserDto.class));
    }

    @Override
    public void deleteUserById(Integer Id) {
        sysAuthUserDao.deleteById(Id);
    }

    @Override
    public void banUserById(Integer Id) {
        sysAuthUserDao.banUserById(Id);
    }

    @Override
    public void unBanUserById(Integer id) {
        sysAuthUserDao.unBanUserById(id);
    }

    @Override
    public void addRoleToUser(Integer userId, Integer roleId) {
        SysAuthUserRoleEntity sysAuthUserRoleEntity = SysAuthUserRoleEntity.builder().roleId(roleId).userId(userId).build();
        sysAuthUserRoleRepository.save(sysAuthUserRoleEntity);
    }

    @Override
    public void removeRoleFromUser(Integer userId, Integer roleId) {
        sysAuthUserRoleRepository.deleteByUserIdAndRoleId(userId, roleId);
    }

    @Override
    public void addUser(SysAuthUserDto user) {
        SysAuthUserEntity sysAuthUserEntity = modelMapper.map(user, SysAuthUserEntity.class);
        sysAuthUserEntity.setPassword(passwordEncoder.encode(user.getPassword()));
        sysAuthUserEntity.setIsBan((byte) 0);
        sysAuthUserDao.save(sysAuthUserEntity);
    }

    @Override
    public void updateUser(SysAuthUserDto user) {
        SysAuthUserEntity sysAuthUserEntity = modelMapper.map(user, SysAuthUserEntity.class);
        //TODO 基于字段进行修改. 更新有的相关属性.
    }

    @Override
    public void changePassword(String userName, String oldPassword, String newPassword) {

    }

    @Override
    public void resetPassword(String userName, String newPassword) {

    }

    @Override
    public void changeUserName(String userName, String newUserName) {

    }

    @Override
    public void changeEmail(String userName, String email) {

    }

    @Override
    public void changePhone(String userName, String phone) {

    }

    @Override
    @Transactional
    @Cacheable(value = "sys::common::user", key = "#token",sync = true)
    public SysAuthUserDto getUserInfoByToken(String token) {
        String email = jwtTokenService.extractUserName(token.replace("Bearer ", ""));
        if (email == null) {
            throw new IllegalArgumentException("Invalid token");
        }
        Optional<SysAuthUserEntity> sysAuthUserOpt =  sysAuthUserDao.findByEmail(email);
        if (sysAuthUserOpt.isPresent()){
            log.debug(sysAuthUserOpt.get().toString());
            SysAuthUserEntity sysAuthUserEntity = sysAuthUserOpt.get();
            return modelMapper.map(sysAuthUserEntity, SysAuthUserDto.class);
        }else{
            throw new IllegalArgumentException("Invalid token");
        }
    }

}
